﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Windows.Forms.DataVisualization.Charting;
using AmCharts.Windows.Column;
using System.Drawing.Drawing2D;
using System.Windows.Forms;

namespace MundoDigital
{
    public class clsImagem
    {
        public Bitmap BtmImagem { get; set; }
        public Bitmap bp1 { get; set; }
        public Bitmap bp2 { get; set; }
        public Bitmap bp3 { get; set; }
        public Bitmap bp4 { get; set; }
        public Bitmap bp5 { get; set; }
        public Bitmap bp6 { get; set; }
        public Bitmap bp7 { get; set; }
        public Bitmap bp8 { get; set; }
        public Bitmap bp9 { get; set; }
        public Bitmap bp10 { get; set; }

        //bitmaps da imagem trabalho 2


        public Bitmap bpRotaciona { get; set; }


        public int[] HistogramaImagemOriginal { get; set; }
        public int[] HistogramaMetadeSuperior { get; set; }
        public int[] HistogramaMetadeInferior { get; set; }
        public int[] HistogramaMetadeEsquerda { get; set; }
        public int[] HistogramaMetadeDireita { get; set; }

        public double MediaImagemOriginal { get; set; }
        public int MedianaImagemOriginal { get; set; }
        public int ModaImagemOriginal { get; set; }
        public double VarianciaImagemOriginal { get; set; }
        public int TotalPixelsImagemOriginal { get; set; }
        public int SomaPixelsImagemOriginal { get; set; }

        public double MediaMetadeSuperior { get; set; }
        public int MedianaMetadeSuperior { get; set; }
        public int ModaMetadeSuperior { get; set; }
        public double VarianciaMetadeSuperior { get; set; }
        public int TotalPixelsMetadeSuperior { get; set; }
        public int SomaPixelsMetadeSuperior { get; set; }

        public double MediaMetadeInferior { get; set; }
        public int MedianaMetadeInferior { get; set; }
        public int ModaMetadeInferior { get; set; }
        public double VarianciaMetadeInferior { get; set; }
        public int TotalPixelsMetadeInferior { get; set; }
        public int SomaPixelsMetadeInferior { get; set; }

        public double MediaMetadeEsquerda { get; set; }
        public int MedianaMetadeEsquerda { get; set; }
        public int ModaMetadeEsquerda { get; set; }
        public double VarianciaMetadeEsquerda { get; set; }
        public int TotalPixelsMetadeEsquerda { get; set; }
        public int SomaPixelsMetadeEsquerda { get; set; }

        public double MediaMetadeDireita { get; set; }
        public int MedianaMetadeDireita { get; set; }
        public int ModaMetadeDireita { get; set; }
        public double VarianciaMetadeDireita { get; set; }
        public int TotalPixelsMetadeDireita { get; set; }
        public int SomaPixelsMetadeDireita { get; set; }

        int metadeLargura { get; set; }
        int metadeAltura { get; set; }

        //Variancias e Medianas
        int[] vetorPixeisOriginal = new int[256];
        int[] vetorPixeisSuperior = new int[256];
        int[] vetorPixeisInferior = new int[256];
        int[] vetorPixeisEsquerda = new int[256];
        int[] vetorPixeisDireita = new int[256];


        public clsImagem(Bitmap btm)
        {
            this.BtmImagem = btm;
            CarregaDados();
        }

        private void CarregaDados()
        {
            CarregaHistogramas();

            //Total de Pixel
            this.TotalPixelsImagemOriginal = BtmImagem.Width * BtmImagem.Height;
            this.TotalPixelsMetadeSuperior = BtmImagem.Width * metadeAltura;
            this.TotalPixelsMetadeInferior = BtmImagem.Width * (BtmImagem.Height - metadeAltura);
            this.TotalPixelsMetadeEsquerda = BtmImagem.Height * metadeLargura;
            this.TotalPixelsMetadeDireita = BtmImagem.Height * (BtmImagem.Width - metadeLargura);

            //Médias
            this.MediaImagemOriginal = SomaPixelsImagemOriginal / TotalPixelsImagemOriginal;
            this.MediaMetadeSuperior = SomaPixelsMetadeSuperior / TotalPixelsMetadeSuperior;
            this.MediaMetadeInferior = SomaPixelsMetadeInferior / TotalPixelsMetadeInferior;
            this.MediaMetadeEsquerda = SomaPixelsMetadeEsquerda / TotalPixelsMetadeEsquerda;
            this.MediaMetadeDireita = SomaPixelsMetadeDireita / TotalPixelsMetadeDireita;

            //Variancias e Medianas

            ProcessaHistograma(BtmImagem);

            this.VarianciaImagemOriginal = CalculaVariancia(HistogramaImagemOriginal, MediaImagemOriginal, TotalPixelsImagemOriginal);

            this.MedianaImagemOriginal = CalculaMediana(vetorPixeisOriginal);


            this.VarianciaMetadeSuperior = CalculaVariancia(HistogramaMetadeSuperior, MediaMetadeSuperior, TotalPixelsMetadeSuperior);

            this.MedianaMetadeSuperior = CalculaMediana(vetorPixeisSuperior);

            this.VarianciaMetadeInferior = CalculaVariancia(HistogramaMetadeInferior, MediaMetadeInferior, TotalPixelsMetadeInferior);

            this.MedianaMetadeInferior = CalculaMediana(vetorPixeisInferior);

            this.VarianciaMetadeEsquerda = CalculaVariancia(HistogramaMetadeEsquerda, MediaMetadeEsquerda, TotalPixelsMetadeEsquerda);

            this.MedianaMetadeEsquerda = CalculaMediana(vetorPixeisEsquerda);

            this.VarianciaMetadeDireita = CalculaVariancia(HistogramaMetadeDireita, MediaMetadeDireita, TotalPixelsMetadeDireita);

            this.MedianaMetadeDireita = CalculaMediana(vetorPixeisDireita);


            //Modas
            ModaImagemOriginal = CalculaModa(vetorPixeisOriginal);

            ModaMetadeSuperior = CalculaModa(HistogramaMetadeSuperior);

            ModaMetadeInferior = CalculaModa(HistogramaMetadeInferior);

            ModaMetadeEsquerda = CalculaModa(HistogramaMetadeEsquerda);

            ModaMetadeDireita = CalculaModa(HistogramaMetadeDireita);

        }

        private void CarregaHistogramas()
        {
            metadeLargura = Convert.ToInt32(Math.Round(Convert.ToDouble(this.BtmImagem.Width) / 2, 0));
            metadeAltura = Convert.ToInt32(Math.Round(Convert.ToDouble(this.BtmImagem.Height) / 2, 0));

            HistogramaImagemOriginal = new int[256];
            HistogramaMetadeDireita = new int[256];
            HistogramaMetadeEsquerda = new int[256];
            HistogramaMetadeInferior = new int[256];
            HistogramaMetadeSuperior = new int[256];

            for (int x = 0; x < this.BtmImagem.Width; x++)
            {
                for (int y = 0; y < this.BtmImagem.Height; y++)
                {
                    byte R = this.BtmImagem.GetPixel(x, y).R;
                    byte G = this.BtmImagem.GetPixel(x, y).G;
                    byte B = this.BtmImagem.GetPixel(x, y).B;

                    int pixel = (R + G + B) / 3;

                    this.HistogramaImagemOriginal[pixel] += 1;
                    this.SomaPixelsImagemOriginal += pixel;

                    if (y < metadeAltura)
                    {
                        this.HistogramaMetadeSuperior[pixel] += 1;
                        this.SomaPixelsMetadeSuperior += pixel;
                    }
                    else
                    {
                        this.HistogramaMetadeInferior[pixel] += 1;
                        this.SomaPixelsMetadeInferior += pixel;

                    }

                    if (x < metadeLargura)
                    {
                        this.HistogramaMetadeEsquerda[pixel] += 1;
                        this.SomaPixelsMetadeEsquerda += pixel;
                    }
                    else
                    {
                        this.HistogramaMetadeDireita[pixel] += 1;
                        this.SomaPixelsMetadeDireita += pixel;
                    }
                }
            }
        }

        public double CalculaVariancia(int[] vetorHist, double media, int totalPixel)
        {
            double soma = 0;
            /* a variavel i possui o papel do valor do pixel ref. ao histograma */

            int totalReg = 0;
            foreach (int v in vetorHist)
            {
                /* considera para o calculo apenas as posisoes que possuem valores */
                //if (v > 0)
                //{
                if (v > 0)
                {
                    for (int i = 0; i < v; i++)
                    {
                        soma += ((i - media) * (i - media));
                    }
                }
                //soma = soma + ((v - media) * (v - media));
                // totalReg = totalReg + v;
                //}
                //i++;
            }
            //if (totalReg > 0)
            //{
            double aux = soma / totalPixel;
            return Math.Round(soma / totalPixel, 0);

            //}
            // else
            //{
            // return 0;
            //
        }

        public static int CalculaMediana(int[] values)
        {
            int total = 0;
            int n = values.Length;

            for (int i = 0; i < n; i++)
            {
                total += values[i];
            }

            int pontoMeio = total / 2;
            int v = 0;
            int mediana = 0;

            for (; mediana < n; mediana++)
            {
                v += values[mediana];
                if (v >= pontoMeio)
                    break;
            }

            return mediana;
        }

        public static double CalculaEntropia(int[] values)
        {
            /* entropia (medida do nível de desordem no sistema; 
             * na termodinâmica-medida da quantidade de energia que não está avaliável ao trabalho) */
            int n = values.Length;
            int total = 0;
            double entropia = 0;
            double p;

            for (int i = 0; i < n; i++)
            {
                total += values[i];
            }

            for (int i = 0; i < n; i++)
            {
                p = (double)values[i] / total;
                if (p != 0)
                    entropia += (-p * Math.Log(p, 2));
            }
            return entropia;
        }

        public static int CalculaModa(int[] vetorHist)
        {
            int maiorInteiro = 0;
            List<int> Modas = new List<int>();

            for (int i = 0; i < vetorHist.Length; i++)
            {
                if (vetorHist[i] > maiorInteiro)
                {
                    Modas.Clear();
                    Modas.Add(i);
                    maiorInteiro = vetorHist[i];
                }
                else if (vetorHist[i] == maiorInteiro)
                {
                    Modas.Add(vetorHist[i]);
                }
            }

            return Modas.Max();
        }

        public void EditaImagem(Bitmap btm, clsImagem ima)
        {
            bp1 = new Bitmap(btm.Width, btm.Height);
            bp2 = new Bitmap(btm.Width, btm.Height);
            bp3 = new Bitmap(btm.Width, btm.Height);
            bp4 = new Bitmap(btm.Width, btm.Height);
            bp5 = new Bitmap(btm.Width, btm.Height);
            bp6 = new Bitmap(btm.Width, btm.Height);
            bp7 = new Bitmap(btm.Width, btm.Height);
            bp8 = new Bitmap(btm.Width, btm.Height);
            bp9 = new Bitmap(btm.Width, btm.Height);
            bp10 = new Bitmap(btm.Width, btm.Height);

            for (int x = 0; x < btm.Width; x++)
            {
                for (int y = 0; y < btm.Height; y++)
                {
                    byte R = btm.GetPixel(x, y).R;
                    byte G = btm.GetPixel(x, y).G;
                    byte B = btm.GetPixel(x, y).B;

                    int pixel = (R + G + B) / 3;

                    //a)	Valores maiores ou iguais a média da metade superior recebem 255.
                    //b)	Valores maiores ou iguais a moda da metade esquerda recebem 255.
                    //c)	Valores maiores ou iguais a mediana da metade direita recebem 255.
                    //d)	Valores menores que a média de toda a imagem recebem 0.
                    //e)	Valores maiores que a média de toda a imagem recebem 255 e os iguais ou menores recebem 0. 


                    if (pixel >= ima.MediaMetadeSuperior)
                    {
                        bp1.SetPixel(x, y, Color.FromArgb(255, 255, 255));

                        if (y <= metadeAltura)
                            bp6.SetPixel(x, y, Color.FromArgb(255, 255, 255));
                        else
                            bp6.SetPixel(x, y, Color.FromArgb(pixel, pixel, pixel));
                    }
                    else
                    {
                        bp1.SetPixel(x, y, Color.FromArgb(pixel, pixel, pixel));
                        bp6.SetPixel(x, y, Color.FromArgb(pixel, pixel, pixel));
                    }


                    if (pixel >= ima.ModaMetadeEsquerda)
                    {
                        bp2.SetPixel(x, y, Color.FromArgb(255, 255, 255));
                        if (x <= metadeLargura)
                            bp7.SetPixel(x, y, Color.FromArgb(255, 255, 255));
                        else
                            bp7.SetPixel(x, y, Color.FromArgb(pixel, pixel, pixel));
                    }
                    else
                    {
                        bp2.SetPixel(x, y, Color.FromArgb(pixel, pixel, pixel));
                        bp7.SetPixel(x, y, Color.FromArgb(pixel, pixel, pixel));
                    }


                    if (pixel >= ima.MedianaMetadeDireita)
                    {
                        bp3.SetPixel(x, y, Color.FromArgb(255, 255, 255));
                        if (x > metadeLargura)
                            bp8.SetPixel(x, y, Color.FromArgb(255, 255, 255));
                        else
                            bp8.SetPixel(x, y, Color.FromArgb(pixel, pixel, pixel));
                    }
                    else
                    {
                        bp3.SetPixel(x, y, Color.FromArgb(pixel, pixel, pixel));
                        bp8.SetPixel(x, y, Color.FromArgb(pixel, pixel, pixel));
                    }


                    if (pixel < ima.MedianaImagemOriginal)
                    {
                        bp4.SetPixel(x, y, Color.FromArgb(0, 0, 0));
                        bp9.SetPixel(x, y, Color.FromArgb(0, 0, 0));
                    }
                    else
                    {
                        bp4.SetPixel(x, y, Color.FromArgb(pixel, pixel, pixel));
                        bp9.SetPixel(x, y, Color.FromArgb(pixel, pixel, pixel));
                    }


                    if (pixel > ima.MediaImagemOriginal)
                    {
                        bp5.SetPixel(x, y, Color.FromArgb(255, 255, 255));
                        bp10.SetPixel(x, y, Color.FromArgb(255, 255, 255));
                    }
                    else
                    {
                        bp5.SetPixel(x, y, Color.FromArgb(0, 0, 0));
                        bp10.SetPixel(x, y, Color.FromArgb(0, 0, 0));
                    }

                }

            }

        }

        // Carrega o vetor com a quantidade de cada pixel
        public void ProcessaHistograma(Bitmap bmp)
        {
            int width = bmp.Width;
            int height = bmp.Height;

            for (int i = 0; i < vetorPixeisOriginal.Length; i++)
            {
                vetorPixeisOriginal[i] = 0;
            }

            int widthM1 = width - 1;
            int heightM1 = height - 1;

            for (int y = 1; y < heightM1; y++)
            {
                for (int x = 1; x < widthM1; x++)
                {
                    byte R = bmp.GetPixel(x, y).R;
                    byte G = bmp.GetPixel(x, y).G;
                    byte B = bmp.GetPixel(x, y).B;

                    int pixel = (R + G + B) / 3;
                    vetorPixeisOriginal[pixel]++;

                    if (y < metadeAltura)
                    {
                        vetorPixeisSuperior[pixel]++;
                    }
                    else
                    {
                        vetorPixeisInferior[pixel]++;
                    }

                    if (x < metadeLargura)
                    {
                        vetorPixeisEsquerda[pixel]++;
                    }
                    else
                    {
                        vetorPixeisDireita[pixel]++;
                    }
                }
            }
        }

        public void CarregaHistogramas(Bitmap bmp)
        {
            int width = bmp.Width;
            int height = bmp.Height;

            for (int i = 0; i < vetorPixeisOriginal.Length; i++)
            {
                vetorPixeisOriginal[i] = 0;
            }

            int widthM1 = width - 1;
            int heightM1 = height - 1;

            for (int y = 1; y < heightM1; y++)
            {
                for (int x = 1; x < widthM1; x++)
                {
                    byte R = bmp.GetPixel(x, y).R;
                    byte G = bmp.GetPixel(x, y).G;
                    byte B = bmp.GetPixel(x, y).B;

                    int pixel = (R + G + B) / 3;
                    vetorPixeisOriginal[pixel]++;

                    if (y < metadeAltura)
                    {
                        vetorPixeisSuperior[pixel]++;
                    }
                    else
                    {
                        vetorPixeisInferior[pixel]++;
                    }

                    if (x < metadeLargura)
                    {
                        vetorPixeisEsquerda[pixel]++;
                    }
                    else
                    {
                        vetorPixeisDireita[pixel]++;
                    }
                }
            }
        }

        //Espelha a imagem
        public static Bitmap EspelhaIMagem(Bitmap bmp)
        {
            int widthM1 = bmp.Width - 1;
            int heightM1 = bmp.Height - 1;

            Bitmap bpEspelho = new Bitmap(widthM1, heightM1);

            //

            for (int y = 1; y < heightM1; y++)
            {
                for (int x = 1; x < widthM1; x++)
                {
                    bpEspelho.SetPixel(widthM1 - x, y, bmp.GetPixel(x, y));
                }
            }

            return bpEspelho;
        }

        //Desloca a imagem
        public static Bitmap DeslocaIMagem(Bitmap bmp, int cima, int lateral)
        {
            int widthM1 = bmp.Width - lateral;
            int heightM1 = bmp.Height - cima;

            Bitmap bpDeslocado = new Bitmap(widthM1, heightM1);

            //

            for (int y = 1; y < heightM1; y++)
            {
                for (int x = 1; x < widthM1; x++)
                {
                    bpDeslocado.SetPixel(x, y, bmp.GetPixel(x + lateral, y + cima));
                }
            }

            return bpDeslocado;
        }

        //Rotaciona a imagem
        public static Bitmap GiraImagem(Bitmap bmp, float angulo)
        {
            Bitmap Retorno = new Bitmap(bmp.Width, bmp.Height);

            //cria um objeto graphics para a imagem vazia
            using (Graphics g = Graphics.FromImage(Retorno))
            {
                // muda a rotação do ponto central da imagem
                g.TranslateTransform((float)bmp.Width / 2, (float)bmp.Height / 2);

                // gira imagem
                g.RotateTransform(angulo);
                //gira a imagem para traz
                g.TranslateTransform(-(float)bmp.Width / 2, -(float)bmp.Height / 2);

                //desenha a nova imagem
                g.DrawImage(bmp, new Point(0, 0));
            }

            return Retorno;
        }

        //amplia ou reduz a imagem
        public static Bitmap RedimensionaImagem(Bitmap bmp, float tamanho)
        {
            // Bitmap para nova imagem com 50% do tamanho original
            Bitmap modificada = new Bitmap((int)(tamanho * bmp.Width), (int)(tamanho * bmp.Height));
            // Redimensiona imagem
            Graphics g = Graphics.FromImage(modificada);
            g.DrawImage(bmp, new Rectangle(0, 0, modificada.Width, modificada.Height), 0, 0, bmp.Width, bmp.Height, GraphicsUnit.Pixel);
            g.Dispose();

            return modificada;
        }

        //Balacas da seleção de imagem

        public static Bitmap Crop(Bitmap image, Rectangle selection)
        {
            Bitmap bmp = image as Bitmap;

            // Crop the image:
            Bitmap cropBmp = bmp.Clone(selection, bmp.PixelFormat);

            // Release the resources:
            image.Dispose();

            return cropBmp;
        }

        public static Bitmap Fit2PictureBox(Bitmap image, PictureBox picBox)
        {
            Bitmap bmp = null;
            Graphics g;

            int aux = image.Width;

            // Scale:
            double scaleY = (double)image.Width / picBox.Width;
            double scaleX = (double)image.Height / picBox.Height;
            double scale = scaleY < scaleX ? scaleX : scaleY;

            // Create new bitmap:
            bmp = new Bitmap(
                (int)((double)image.Width / scale),
                (int)((double)image.Height / scale));

            // Set resolution of the new image:
            bmp.SetResolution(
                image.HorizontalResolution,
                image.VerticalResolution);

            // Create graphics:
            g = Graphics.FromImage(bmp);

            // Set interpolation mode:
            g.InterpolationMode = InterpolationMode.HighQualityBicubic;

            // Draw the new image:
            g.DrawImage(
                image,
                new Rectangle(            // Destination
                    0, 0,
                    bmp.Width, bmp.Height),
                new Rectangle(    
                    0, 0,
                    image.Width, image.Height),
                GraphicsUnit.Pixel);

            // Release the resources of the graphics:
            g.Dispose();

            // Release the resources of the origin image:
            image.Dispose();

            return bmp;
        }
    }
}
